/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.raflik.queryxml.serializer.standard;

import pl.raflik.queryxml.lib.ResultType;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
import org.openide.util.NbBundle;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import pl.raflik.queryxml.lib.XMLNodePresenter;
import pl.raflik.queryxml.serializer.QueryResultSerializeException;

/**
 *
 * @author raflik
 */
public class TextTransformer extends AbstractTransformer {

    private static final String FIRST_SEPARATOR_DEFAULT = ": ";
    private static final String SECOND_SEPARATOR_DEFAULT = " ";
    private static final String FIRST_SEPARATOR_PREF_KEY = "FIRST_SEPARATOR_PREF_KEY";
    private static final String SECOND_SEPARATOR_PREF_KEY = "SECOND_SEPARATOR_PREF_KEY";

    public static String getFirstSeparator() {
        return PrefUtil.getStringSetting(TextTransformer.class, FIRST_SEPARATOR_PREF_KEY, FIRST_SEPARATOR_DEFAULT);
    }

    public static String getSecondSeparator() {
        return PrefUtil.getStringSetting(TextTransformer.class, SECOND_SEPARATOR_PREF_KEY, SECOND_SEPARATOR_DEFAULT);
    }

    public static void setFirstSeparator(String separator) {
        PrefUtil.setStringSetting(TextTransformer.class, FIRST_SEPARATOR_PREF_KEY, separator);
    }

    public static void setSecondSeparator(String separator) {
        PrefUtil.setStringSetting(TextTransformer.class, SECOND_SEPARATOR_PREF_KEY, separator);
    }
    
    //private static int ITEM_MAX_LENGTH = 100;
    private static Class<?>[] primitiveTypes = new Class[]{Boolean.class, Number.class, String.class};

    private String formatItem(Class clazz, String string) {
        String text = ResultType.formatType(clazz);
        String firstSeparator = getFirstSeparator();
        if (text != null) {
            StringBuilder sb = new StringBuilder();
            sb.append(text);
            sb.append(firstSeparator);
            sb.append(string);
            //text = text.substring(0, Math.min(text.length(), ITEM_MAX_LENGTH));
            return sb.toString();
        }
        return null;
    }

    private String getNodeItem(Node node) {
        StringBuilder sb = new StringBuilder();
        sb.append(XMLNodePresenter.getNodeName(node));
        final String value = XMLNodePresenter.getNodeValue(node);
        String secondSeparator = getSecondSeparator();
        if (value.length() > 0) {
            sb.append(secondSeparator);
            sb.append(value);
        }
        return sb.toString();
    }

    private void writeSingleObj(Object output, PrintWriter pw) {
        if (output instanceof Node) {
            Node node = (Node) output;
            writeNode(node, pw);
        } else {
            boolean found = false;
            for (int i = 0; i < primitiveTypes.length; i++) {
                Class<?> primitiveClazz = primitiveTypes[i];
                Class<?> outputClazz = output.getClass();
                if (primitiveClazz.isAssignableFrom(outputClazz)) {
                    found = true;
                    break;
                }
            }
            if (found) {
                writePrimitive(output, pw);
            }
        }
    }

    private void writeObj(Object output, PrintWriter pw) {
        if (output instanceof NodeList) {
            NodeList xmlNodeList = (NodeList) output;
            for (int i = 0; i < xmlNodeList.getLength(); i++) {
                Node xmlNode = xmlNodeList.item(i);
                writeNode(xmlNode, pw);
            }
        } else if (output instanceof List) {
            List list = (List) output;
            for (Object obj : list) {
                writeSingleObj(obj, pw);
            }
        } else {
            writeSingleObj(output, pw);
        }
    }

    private void writeNode(Node node, PrintWriter pw) {
        Class clazz = node.getClass();
        String nodeItem = getNodeItem(node);
        String item = formatItem(clazz, nodeItem);
        if (item != null) {
            pw.println(item);
        }
    }

    @Override
    protected void checkSerializeInvocation(List<?> queryResult, OutputStream os, Object param) throws QueryResultSerializeException {
        super.checkSerializeInvocation(queryResult, os, param);
        if (param != null) {
            throw new QueryResultSerializeException("params not supported");
        }
    }

    public void serialize(List<?> queryResult, OutputStream os, Object param) throws QueryResultSerializeException {
        checkSerializeInvocation(queryResult, os, param);

        PrintWriter pw = new PrintWriter(os);
        writeObj(queryResult, pw);
        pw.flush();
    }

    private void writePrimitive(Object output, PrintWriter pw) {
        pw.println(formatItem(output.getClass(), output.toString()));
    }
    private static final Object[] params = new Object[0];

    public Object[] getParams() {
        return params;
    }

    public String getExtension() {
        return "txt"; //NOI18
    }

    public String supportedOutputType() {
        return NbBundle.getMessage(TextTransformer.class, "TextTransformer.supportedOutputType");
    }
}
